package me.exchange.com.modules.system.service.impl;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import me.exchange.com.annotation.Constant;
import me.exchange.com.modules.system.domain.FileContent;
import me.exchange.com.modules.system.dto.FileQueryCriteria;
import me.exchange.com.modules.system.repository.FileContentRepository;
import me.exchange.com.modules.system.service.AmazonService;
import me.exchange.com.utils.*;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;

@Service
public class AmazonServiceImpl implements AmazonService {
    @Autowired
    private AmazonS3Client amazonS3Client;
    @Autowired
    private FileContentRepository fileContentRepository;

    //桶
    @Value("${cloud.aws.s3.bucket}")
    private String bucket;
    //域名
    @Value("${cloud.aws.s3.realm}")
    private String realm;

    public PutObjectResult upload(String filePath, String uploadKey,ObjectMetadata objectMetadata){
        PutObjectResult putObjectResults =null;
        try {
            putObjectResults =upload(new FileInputStream(filePath), uploadKey, objectMetadata);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return putObjectResults;
    }

    public PutObjectResult upload(InputStream inputStream, String uploadKey,ObjectMetadata objectMetadata) {

        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, uploadKey, inputStream, objectMetadata);

        putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);
        PutObjectResult putObjectResult = amazonS3Client.putObject(putObjectRequest);

        IOUtils.closeQuietly(inputStream);

        return putObjectResult;
    }

    @Override
    public List<FileContent> upload(MultipartFile[] multipartFiles) {
        List<FileContent> fileContents = new ArrayList<>();

        Arrays.stream(multipartFiles)
                .filter(multipartFile -> !StringUtils.isEmpty(multipartFile.getOriginalFilename()))
                .forEach(multipartFile -> {
                    try {
                        FileContent fileContent = new FileContent();
                        FileContent new_fileContent = new FileContent();
                        String originalFileName = multipartFile.getOriginalFilename();
                        String suffix =  originalFileName.substring(originalFileName.lastIndexOf(".") );
                        String tempFileName = MD5Util.stringToMD5(multipartFile.getOriginalFilename()+System.currentTimeMillis())+ suffix;
                        String contentType = multipartFile.getContentType();
                        long fileSize = multipartFile.getSize();
                        String filePath = "/"+tempFileName;
                        ObjectMetadata objectMetadata = new ObjectMetadata();
                        objectMetadata.setContentType(contentType);
                        objectMetadata.setContentLength(fileSize);
                        upload(multipartFile.getInputStream(), tempFileName,objectMetadata);
                        //存入数据库
                        fileContent = new FileContent();
                        fileContent.setKey(originalFileName);
                        fileContent.setSuffix(suffix);
                        fileContent.setRealName(tempFileName);
                        fileContent.setType(contentType);
                        fileContent.setBucket(bucket);
                        fileContent.setUrl(realm+filePath);
                        fileContent.setSize(FileUtil.getSize(Integer.parseInt(multipartFile.getSize()+"")));
                        new_fileContent =  fileContentRepository.save(fileContent);
                        fileContents.add(new_fileContent);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });

        return fileContents;
    }
    @Override
    public FileContent upload(MultipartFile multipartFile) {
        PutObjectResult putObjectResult =new PutObjectResult();
        FileContent fileContent = new FileContent();
        FileContent new_fileContent = new FileContent();
        try {

            String originalFileName = multipartFile.getOriginalFilename();
            String suffix =  originalFileName.substring(originalFileName.lastIndexOf("."));
            String tempFileName = MD5Util.stringToMD5(multipartFile.getOriginalFilename()+System.currentTimeMillis())+ suffix;
            String contentType = multipartFile.getContentType();
            long fileSize = multipartFile.getSize();
            String filePath = "/"+tempFileName;
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentType(contentType);
            objectMetadata.setContentLength(fileSize);
            putObjectResult =upload(multipartFile.getInputStream(), tempFileName,objectMetadata);
            //存入数据库
            fileContent = new FileContent();
            fileContent.setKey(originalFileName);
            fileContent.setSuffix(suffix);
            fileContent.setRealName(tempFileName);
            fileContent.setType(Constant.FILE_TYPE_ENUM.getValue(contentType));
            fileContent.setBucket(bucket);
            fileContent.setUrl(realm+filePath);
            fileContent.setSize(FileUtil.getSize(Integer.parseInt(multipartFile.getSize()+"")));
            new_fileContent =  fileContentRepository.save(fileContent);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return new_fileContent;
    }

    @Override
    public ResponseEntity<byte[]> download(String key) throws IOException {
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key);

        S3Object s3Object = amazonS3Client.getObject(getObjectRequest);

        S3ObjectInputStream objectInputStream = s3Object.getObjectContent();

        byte[] bytes = IOUtils.toByteArray(objectInputStream);

        String fileName = URLEncoder.encode(key, "UTF-8").replaceAll("\\+", "%20");

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        httpHeaders.setContentLength(bytes.length);
        httpHeaders.setContentDispositionFormData("attachment", fileName);

        return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK);
    }

    @Override
    public List<S3ObjectSummary> list() {
        ObjectListing objectListing = amazonS3Client.listObjects(new ListObjectsRequest().withBucketName(bucket));

        List<S3ObjectSummary> s3ObjectSummaries = objectListing.getObjectSummaries();

        return s3ObjectSummaries;
    }

    @Override
    public Object queryAll(FileQueryCriteria criteria, Pageable pageable){
        return PageUtil.toPage(fileContentRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable));
    }

    @Override
    public List<FileContent> queryAll(FileQueryCriteria criteria){
        return fileContentRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
    }

    @Override
    @Cacheable
    public FileContent findByContentId(Long id) {
        FileContent FileContent = fileContentRepository.findById(id).orElseGet(FileContent::new);
        ValidationUtil.isNull(FileContent.getId(),"FileContent", "id",id);
        return FileContent;
    }

    @Override
    public void downloadList(List<FileContent> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (FileContent content : queryAll) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("文件名", content.getKey());
            map.put("文件类型", content.getSuffix());
            map.put("空间名称", content.getBucket());
            map.put("文件大小", content.getSize());
            map.put("空间类型", content.getType());
            map.put("创建日期", content.getUAdminTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}